function test() {
    var person = {};
    person.name = "Bobby";
    person.age = 26;

    var person2 = {name: "Bobby", age: 26};

    var person3 = {
        "name": "Bobby",
        "age": 26,
        5: true
    };
}

function displayInfo(args) {
    var output = "";
    if (typeof args.name === "string") {
        output += "Name: " + args.name + "\n";
    }
    if (typeof args.age === "number") {
        output += "Age: " + args.age + "\n";
    }
    alert(output);
}

function objectTest() {
    displayInfo({name: "Nicholas", age: 26});
    displayInfo({name: "Greg"});
}

function arrayTest() {
    var colors1 = new Array(20);
    var names = new Array("Greg");
    var colors = ["red", "blue", "green"];
    colors.length = 2;
    alert(colors[2]); //undefined
    colors[colors.length] = "black";
    alert(colors);

    var colors = []; //创建一个数组
    var count = colors.push("red", "green"); //推入两项
    alert("push:" + colors);
    colors.unshift("red2", "green2"); //推入两项
    alert("unshift:" + colors);


}

function compare(value1, value2) {
    return value1 - value2;
}

function sortTest() {
    var values = [1, 2, 3, 4, 5];
    values.reverse();

    var values = [0, 1, 5, 10, 15];
    values.sort();//排序前转成了字符串
    alert(values); //0,1,10,15,5
    values.sort(compare);
    alert(values); //0,1,5,10,15
}

function concatTest() {
    var colors = ["red", "green", "blue"];
    var colors2 = colors.concat("yellow", ["black", "brown"]);
    alert(colors); //red,green,blue
    alert(colors2); //red,green,blue,yellow,black,brown
    alert("colors2.length:" + colors2.length);
}

function sliceTest() {
    var colors = ["red", "green", "blue", "yellow", "purple"];
    var colors2 = colors.slice(1);
    var colors3 = colors.slice(1, 4);
    alert(colors2); //green,blue,yellow,purple
    alert(colors3); //green,blue,yellow
}

function spliceTest() {
    var colors = ["red", "green", "blue"];
    var removed = colors.splice(0, 1); // 删除第一项
    alert(colors); // green,blue
    alert(removed); // red，返回的数组中只包含一项
    removed = colors.splice(1, 0, "yellow", "orange"); // 从位置1 开始插入两项
    alert(colors); // green,yellow,orange,blue
    alert(removed); // 返回的是一个空数组
    removed = colors.splice(1, 1, "red", "purple"); // 插入两项，删除一项
    alert(colors); // green,red,purple,orange,blue
    alert(removed); // yellow，返回的数组中只包含一项
}

//位置方法
function indexTest() {
    var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
    alert(numbers.indexOf(4)); //3
    alert(numbers.lastIndexOf(4)); //5
    alert(numbers.indexOf(4, 4)); //5
    alert(numbers.lastIndexOf(4, 4)); //3
    var person = {name: "Nicholas"};
    var people = [{name: "Nicholas"}];
    var morePeople = [person];
    alert(people.indexOf(person)); //-1
    alert(morePeople.indexOf(person)); //0
}

//迭代方法
function iteratorTest() {
    var numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
    //对数组中的每一项运行给定函数，如果该函数对每一项都返回true，则返回true。
    var everyResult = numbers.every(function (item, index, array) {
        return (item > 2);
    });
    alert("numbers.every:" + everyResult); //false
    //对数组中的每一项运行给定函数，如果该函数对任一项返回true，则返回true。
    var someResult = numbers.some(function (item, index, array) {
        return (item > 2);
    });
    alert("numbers.some:" + someResult); //true

    var filterResult = numbers.filter(function (item, index, array) {
        return (item > 2);
    });
    alert(filterResult); //[3,4,5,4,3]

    var mapResult = numbers.map(function (item, index, array) {
        return item * 2;
    });
    alert(mapResult); //[2,4,6,8,10,8,6,4,2]

    var forEachResult = "";
    numbers.forEach(function (item, index, array) {
        //执行某些操作
        forEachResult += "n" + item + " ";
    });
    alert(forEachResult);//n1 n2 n3 n4 n5 n4 n3 n2 n1
}

//归并方法
function mergeTest() {
    var values = [1, 2, 3, 4, 5];
    //从左到右归并
    var sum = values.reduce(function (prev, cur, index, array) {
        return prev + cur;
    });
    alert(sum); //15
    //从右到左归并
    sum = values.reduceRight(function (prev, cur, index, array) {
        return prev + cur;
    });
    alert(sum); //15
}

function dateTest() {
    // GMT 时间2000 年1 月1 日午夜零时
    var y2k = new Date(Date.UTC(2000, 0));
    // GMT 时间2005 年5 月5 日下午5:55:55
    var allFives = new Date(Date.UTC(2005, 4, 5, 17, 55, 55));
    // 本地时间2000 年1 月1 日午夜零时
    var y2k = new Date(2000, 0);
    // 本地时间2005 年5 月5 日下午5:55:55
    var allFives = new Date(2005, 4, 5, 17, 55, 55);
    alert(new Date());
}

function regExpTest() {
    /*
    * 匹配字符串中所有"at"的实例
    */
    var pattern1 = /at/g;
    /*
    * 匹配第一个"bat"或"cat"，不区分大小写
    */
    var pattern2 = /[bc]at/i;
    /*
    * 匹配所有以"at"结尾的3个字符的组合，不区分大小写
    */
    var pattern3 = /.at/gi;
    /*
    * 匹配第一个" [bc]at"，不区分大小写
    */
    var pattern4 = /\[bc]at/i;
    /*
    * 匹配所有".at"，不区分大小写
    */
    var pattern5 = /\.at/gi;

    /*
    * 与pattern2相同，只不过是使用构造函数创建的
    */
    var pattern6 = new RegExp("[bc]at", "i");

    //ECMAScript 5之前效果不同，/cat/g 使用的是同一个RegExp；ECMAScript5之后字面量和RegExp效果相同，都会创建新的实例
    var re = null;
    var i;
    for (i = 0; i < 3; i++) {
        re = /cat/g;
        alert("test1:" + re.test("catastrophe"));
    }

    for (i = 0; i < 3; i++) {
        re = new RegExp("cat", "g");
        alert("test2:" + re.test("catastrophe"));
    }

    var pattern1 = /\[bc]at/i;
    alert(pattern1.global); //false
    alert(pattern1.ignoreCase); //true
    alert(pattern1.multiline); //false
    alert(pattern1.lastIndex); //0
    alert(pattern1.source); //"\[bc\]at"
    var pattern2 = new RegExp("\\[bc\\]at", "i");
    alert(pattern2.global); //false
    alert(pattern2.ignoreCase); //true
    alert(pattern2.multiline); //false
    alert(pattern2.lastIndex); //0
    alert(pattern2.source); //"\[bc\]at"

    var text = "mom and dad and baby";
    var pattern = /mom( and dad( and baby)?)?/gi;
    var matches = pattern.exec(text);
    alert(matches.index); // 0
    alert(matches.input); // "mom and dad and baby"
    alert(matches[0]); // "mom and dad and baby"
    alert(matches[1]); // " and dad and baby"
    alert(matches[2]); // " and baby"

    var text = "cat, bat, sat, fat";
    var pattern1 = /.at/;
    var matches = pattern1.exec(text);
    alert(matches.index); //0
    alert(matches[0]); //cat
    alert(pattern1.lastIndex); //0
    matches = pattern1.exec(text);
    alert(matches.index); //0
    alert(matches[0]); //cat
    alert(pattern1.lastIndex); //0
    var pattern2 = /.at/g;
    var matches = pattern2.exec(text);
    alert(matches.index); //0
    alert(matches[0]); //cat
    alert(pattern2.lastIndex); //3
    matches = pattern2.exec(text);
    alert(matches.index); //5
    alert(matches[0]); //bat
    alert(pattern2.lastIndex); //8

    var text = "000-00-0000";
    var pattern = /\d{3}-\d{2}-\d{4}/;
    if (pattern.test(text)) {
        alert("The pattern was matched.");
    }

    var text = "this has been a short summer";
    var pattern = /(.)hort/g;
    /*
    * 注意：Opera 不支持input、lastMatch、lastParen 和multiline 属性
    * Chrome Internet Explorer 不支持multiline 属性
    */
    if (pattern.test(text)) {
        alert(RegExp.input); // this has been a short summer
        alert(RegExp.leftContext); // this has been a
        alert(RegExp.rightContext); // summer
        alert(RegExp.lastMatch); // short
        alert(RegExp.lastParen); // s
        alert(RegExp.multiline); // false
    }

    var pattern = /(.)hort/g;
    if (pattern.test(text)) {
        // alert(RegExp["$_"]); // this has been a short summer
        alert(RegExp.$_); // this has been a short summer
        alert(RegExp["$`"]); // this has been a
        alert(RegExp["$'"]); // summer
        alert(RegExp["$&"]); // short
        alert(RegExp["$+"]); // s
        alert(RegExp["$*"]); // false
    }

    var text = "this has been a short summer";
    var pattern = /(..)or(.)/g;
    if (pattern.test(text)) {
        alert(RegExp.$1); //sh
        alert(RegExp.$2); //t
    }
}

//函数声明提升
// alert(sum(10, 10));
// function sum(num1, num2) {
//     return num1 + num2;
// }

// 函数表达式无法提升
// alert(sum(10,10));
// var sum = function(num1, num2){
//     return num1 + num2;
// };


function createComparisonFunction(propertyName) {
    return function (object1, object2) {
        var value1 = object1[propertyName];
        var value2 = object2[propertyName];
        if (value1 < value2) {
            return -1;
        } else if (value1 > value2) {
            return 1;
        } else {
            return 0;
        }
    };
}

function functionTest() {
    //作为值的函数
    var data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];
    data.sort(createComparisonFunction("name"));
    alert("sort by name:" + data[0].name); //Nicholas
    data.sort(createComparisonFunction("age"));
    alert("sort by age:" + data[0].name); //Zachary

    //原引用被保存
    var trueFactorial = factorial;
    factorial = function () {
        return 1;
    };
    alert(trueFactorial(5)); //120
    alert(factorial(5)); //1
}

// function factorial(num) {
//     if (num <= 1) {
//         return 1;
//     } else {
//         return num * factorial(num - 1)
//     }
// }

function factorial(num) {
    if (num <= 1) {
        return 1;
    } else {
        return num * arguments.callee(num - 1)
    }
}

//this用法
// window.color = "red";
// var o = { color: "blue" };
// function sayColor(){
//     alert(this.color);
// }
// sayColor(); //"red"
// o.sayColor = sayColor;
// o.sayColor(); //"blue"

//caller用法
// function outer() {
//     inner();
// }
// function inner() {
//     // alert(inner.caller);
//     alert(arguments.callee.caller);
// }
// outer();

//apply用法
// function sum(num1, num2){
//     return num1 + num2;
// }
// function callSum1(num1, num2){
//     return sum.apply(this, arguments); // 传入arguments 对象
// }
// function callSum2(num1, num2){
//     return sum.apply(this, [num1, num2]); // 传入数组
// }
// alert(callSum1(10,10)); //20
// alert(callSum2(10,10)); //20

//call用法
// function sum(num1, num2){
//     return num1 + num2;
// }
// function callSum(num1, num2){
//     return sum.call(this, num1, num2);
// }
// alert(callSum(10,10)); //20
//
// window.color = "red";
// var o = { color: "blue" };
// function sayColor(){
//     alert(this.color);
// }
// sayColor(); //red
// sayColor.call(this); //red
// sayColor.call(window); //red
// sayColor.call(o); //blue

//ES5 bind
// window.color = "red";
// var o = { color: "blue" };
// function sayColor(){
//     alert(this.color);
// }
// var objectSayColor = sayColor.bind(o);
// objectSayColor(); //blue

function stringTest() {
    var s1 = "some text";
    s1.color = "red";
    alert("s1.color:" + s1.color); //undefined
    alert(typeof String(s1));//string
    var s2 = new String(s1);//Object
    alert(typeof s2);
    s2.color = "red";
    alert("s2.color:" + s2.color); //red

    alert(s1.charAt(1)); //"o"
    alert(s1.charCodeAt(1));
    alert(s1[1]); //"o" 如果是在IE7 及更早版本中使用这种语法，会返回undefined

    var stringValue = "hello world";
    alert(stringValue.slice(3)); //"lo world"
    alert(stringValue.substring(3)); //"lo world"
    alert(stringValue.substr(3)); //"lo world"
    alert(stringValue.slice(3, 7)); //"lo w"
    alert(stringValue.substring(3, 7)); //"lo w"
    alert(stringValue.substr(3, 7)); //"lo worl"

    // -3 --> 11-3=8
    alert(stringValue.slice(-3)); //"rld"
    // -3 --> 0
    alert(stringValue.substring(-3)); //"hello world"
    // -3 --> 11-3=8
    alert(stringValue.substr(-3)); //"rld"
    // (3, -4) --> (3, 7)
    alert(stringValue.slice(3, -4)); //"lo w"
    // (3, -4) --> (3, 0)
    alert(stringValue.substring(3, -4)); //"hel"
    // (3, -4) --> (3, 0)
    alert(stringValue.substr(3, -4)); //""（空字符串）
}

function numberTest() {
    var value = "25";
    var number = Number(value); //转型函数
    alert(typeof number); //"number"
    var obj = new Number(value); //构造函数
    alert(typeof obj); //"object"
    // alert(obj.toString()); //"25"
    // alert(obj.toString(2)); //"11001"
    // alert(obj.toString(8)); //"31"
    // alert(obj.toString(10)); //"25"
    // alert(obj.toString(16)); //"19"
    alert("toFixed: " + obj.toFixed(2)); //"25.00"
    alert("toExponential: " + obj.toExponential(1)); //"2.5e+1"
    alert("toPrecision(1): " + obj.toPrecision(1)); //"3e+1"
    alert("toPrecision(2): " + obj.toPrecision(2)); //"25"
    alert("toPrecision(3): " + obj.toPrecision(3)); //"25.0"
}

function booleanTest() {
    var falseObject = new Boolean(false);
    var result = falseObject.valueOf() && true;
    alert(result); //true
    var falseValue = false;
    result = falseValue && true;
    alert(result); //false

    alert(typeof falseObject); //object
    alert(typeof falseValue); //boolean
    alert(falseObject instanceof Boolean); //true
    alert(falseValue instanceof Boolean); //false
}

function stringRegExpTest() {
    var text = "cat, bat, sat, fat";
    var pattern = /.at/;
    //与pattern.exec(text)相同
    var matches = text.match(pattern);
    alert(matches.index); //0
    alert(matches[0]); //"cat"
    alert(pattern.lastIndex); //0

    var text = "cat, bat, sat, fat";
    var pos = text.search(/at/);
    alert(pos); //1

    var text = "cat, bat, sat, fat";
    var result = text.replace("at", "ond");
    alert(result); //"cond, bat, sat, fat"
    result = text.replace(/at/g, "ond");
    alert(result); //"cond, bond, sond, fond"

    /*字符序列    替换文本
        $$ $
        $& 匹配整个模式的子字符串。与RegExp.lastMatch的值相同
        $' 匹配的子字符串之前的子字符串。与RegExp.leftContext的值相同
        $` 匹配的子字符串之后的子字符串。与RegExp.rightContext的值相同
        $n 匹配第n个捕获组的子字符串，其中n等于0～9。例如，$1是匹配第一个捕获组的子字符串，$2是匹配第
            二个捕获组的子字符串，以此类推。如果正则表达式中没有定义捕获组，则使用空字符串
        $nn 匹配第nn个捕获组的子字符串，其中nn等于01～99。例如，$01是匹配第一个捕获组的子字符串，$02
            是匹配第二个捕获组的子字符串，以此类推。如果正则表达式中没有定义捕获组，则使用空字符串
    */
    var text = "cat, bat, sat, fat";
    result = text.replace(/(.at)/g, "word ($1)");
    alert(result); //word (cat), word (bat), word (sat), word (fat)

    function htmlEscape(text) {
        return text.replace(/[<>"&]/g, function (match, pos, originalText) {
            switch (match) {
                case "<":
                    return "&lt;";
                case ">":
                    return "&gt;";
                case "&":
                    return "&amp;";
                case "\"":
                    return "&quot;";
            }
        });
    }

    alert(htmlEscape("<p class=\"greeting\">Hello world!</p>"));
    //&lt;p class=&quot;greeting&quot;&gt;Hello world!&lt;/p&gt;

    var colorText = "red,blue,green,yellow";
    var colors1 = colorText.split(","); //["red", "blue", "green", "yellow"]
    var colors2 = colorText.split(",", 2); //["red", "blue"]
    //以，以外的字符分隔
    var colors3 = colorText.split(/[^,]+/); //["", ",", ",", ",", ""]

    // anchor(name) <a name= "name">string</a>
    // big() <big>string</big>
    // bold() <b>string</b>
    // fixed() <tt>string</tt>
    // fontcolor(color) <font color="color">string</font>
    // fontsize(size) <font size="size">string</font>
    // italics() <i>string</i>
    // link(url) <a href="url">string</a>
    // small() <small>string</small>
    // strike() <strike>string</strike>
    // sub() <sub>string</sub>
    // sup() <sup>string</sup>
}

function globalTest() {
    var uri = "http://www.wrox.com/illegal value.htm#start";
    //"http://www.wrox.com/illegal%20value.htm#start"
    alert(encodeURI(uri));
    //"http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start"
    alert(encodeURIComponent(uri));

    var uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start";
    //http%3A%2F%2Fwww.wrox.com%2Fillegal value.htm%23start
    alert(decodeURI(uri));
    //http://www.wrox.com/illegal value.htm#start
    alert(decodeURIComponent(uri));

    //取得Global 对象
    var global = function () {
        return this;
    }();
}

function evalTest() {
    eval("alert('hi')");
    eval("function sayHi() { alert('sayHi()'); }");
    sayHi();
    eval("var msg = 'hello world'; ");
    alert(msg); //"hello world"
}


function mathTest() {
    var max = Math.max(3, 54, 32, 16);
    alert(max); //54
    var min = Math.min(3, 54, 32, 16);
    alert(min); //3
    var values = [1, 2, 3, 4, 5, 6, 7, 8];
    var max = Math.max.apply(Math, values);
    // 这个技巧的关键是把Math 对象作为apply()的第一个参数，从而正确地设置this 值。然后，可
    // 以将任何数组作为第二个参数。

    alert(Math.ceil(25.9)); //26
    alert(Math.ceil(25.5)); //26
    alert(Math.ceil(25.1)); //26
    alert(Math.round(25.9)); //26
    alert(Math.round(25.5)); //26
    alert(Math.round(25.1)); //25
    alert(Math.floor(25.9)); //25
    alert(Math.floor(25.5)); //25
    alert(Math.floor(25.1)); //25

    function selectFrom(lowerValue, upperValue) {
        var choices = upperValue - lowerValue + 1;
        return Math.floor(Math.random() * choices + lowerValue);
    }
    var num = selectFrom(2, 10);
    alert(num); // 介于 2 和10 之间（包括 2 和 10）的一个数值
}